#ifndef _VIRTUAL_DISK_
#define _VIRTUAL_DISK_
/*
#include <ntddk.h>
#include <ntdddisk.h>
#include <ntddcdrm.h>
#include <ntverp.h>
#include <wdmsec.h>
#include <Ntstrsafe.h>

#include <ntddstor.h>
#include <mountdev.h>
#include <ntddvol.h>
*/

#include <ntifs.h>
#include <ntddk.h>
#include <ntdddisk.h>
#include <ntverp.h>
#include <mountmgr.h>
#include <Ntstrsafe.h> 
#include "VD_Crypto.h"

#ifndef __T
#ifdef _NTDDK_
#define __T(x)  L ## x
#endif
#endif

#ifndef _T
#define _T(x)   __T(x)
#endif

// Declare Const for Debugging purposes
#ifndef MY_DBG
#define MY_DBG
#endif


//Global variables

PDRIVER_OBJECT			BaseDriverObject; 
HANDLE					dir_handle;
CONST LONG				BaseDeviceNumber = 0;
CONST LONG				NumberOfDevices  = 26;
CONST USHORT			NumberOfDereferenceAttempts = 10;
CONST LONGLONG			DereferenceAttemptsDelay = -10000000;
CONST LONGLONG			PassOffset	= 512;				
UNICODE_STRING			RegPathW;
WCHAR					DiskDeviceStatus[27] = {0};
const LONG				LONGSIZE = sizeof(LONG);

UCHAR					CryptKey[] = "TestKey";			
CONST ULONG				CryptKeyLen = sizeof(CryptKey) - 1;
UCHAR					DiskIdentification[] = "Genuine MultiVDD";
LONG					DiskIdentificationLen = sizeof(DiskIdentification) - 1;
CONST LONG				NEWDISK = 10;

//FIleSystem types

UCHAR					 NTFS_Disk[] = "NTFS";
UCHAR					 FAT_Disk[] = "MSDOS";

# define   POOL_TAG			'MTag'

// Regisrty names			
# define REG_DEVICE_FILE_NAME	_T("FileName") 
# define REG_DEVICE_FILE_SIZE	_T("FileSize") 
# define REG_DISK_DEVICE_STATUS _T("DiskStatus")

# define REG_PATH_SUB_DIR  _T('\\') 

# define DEVICE_DIR_NAME  _T("\\Device\\HardDisk") 
# define DEVICE_NAME_PREFIX   DEVICE_DIR_NAME _T("\\VirtualDisk_") 

# define MASTER_DEVICE_NAME _T("\\Device\\MasterVirtualDisk") 

#define MULTI_VDD_DOS_DEV             _T("MasterVirtualDisk")
#define MULTI_VDD_SYMLINK_NAME        _T("\\DosDevices\\") MULTI_VDD_DOS_DEV

#define DEVICE_MULTI_VDD       0x8000

//Control codes Create/delete device
#define IOCTL_VD_CREATE_DEVICE  CTL_CODE(DEVICE_MULTI_VDD, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_VD_DELETE_DEVICE  CTL_CODE(DEVICE_MULTI_VDD, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)

//Control codes Open/close file
#define IOCTL_VD_OPEN_FILE   CTL_CODE(DEVICE_MULTI_VDD, 0x802, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define IOCTL_VD_CLOSE_FILE  CTL_CODE(DEVICE_MULTI_VDD, 0x803, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)

// Optioanal Query disk info
#define IOCTL_VD_QUERY_FILE  CTL_CODE(DEVICE_MULTI_VDD, 0x804, METHOD_BUFFERED, FILE_READ_ACCESS)

#define IOCTL_VD_CHECK_FILE  CTL_CODE(DEVICE_MULTI_VDD, 0x806, METHOD_BUFFERED, FILE_READ_ACCESS)

typedef struct _CREATE_DISK_INFO {
	LONGLONG			 FileSize;
	LONG				 FileNameLength;
    PWCHAR				 FileName;
} CREATE_DISK_INFO, *PCREATE_DISK_INFO;

typedef struct _PASSWORD_DATA {
	PWCHAR			    Password;
	LONG				PasLen;
} PASSWORD_DATA, *PPASSWORD_DATA;


#define FSCTL_SET_SPARSE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)

NTSYSAPI
NTSTATUS
NTAPI
ZwFsControlFile (
    IN HANDLE               FileHandle,
    IN HANDLE               Event OPTIONAL,
    IN PIO_APC_ROUTINE      ApcRoutine OPTIONAL,
    IN PVOID                ApcContext OPTIONAL,
    OUT PIO_STATUS_BLOCK    IoStatusBlock,
    IN ULONG                FsControlCode,
    IN PVOID                InputBuffer OPTIONAL,
    IN ULONG                InputBufferLength,
    OUT PVOID               OutputBuffer OPTIONAL,
    IN ULONG                OutputBufferLength
);

typedef struct _DEVICE_EXTENSION {
    BOOLEAN							disk_mounted;
	BOOLEAN							IsDiskRaw;
	BOOLEAN							DeleteDevice;
	LONG							enc_pass_len;
	LONG							PasswordCheck;
	LONG							DiskIDCheck;
    HANDLE							file_handle;
    UNICODE_STRING					file_name;
    LARGE_INTEGER					file_size;
	PUCHAR							password;
	LONG							pas_len;
	LONG							DeviceNumber;
    LIST_ENTRY						list_head;
    KSPIN_LOCK						list_lock;
    KEVENT							request_event;
    PVOID							thread_pointer;
    BOOLEAN							terminate_thread;
	UNICODE_STRING					RegPathName;
	HANDLE							RegPathHandle;
	BLOWFISH_CTX					ctx;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;


// Blowfish algorithm finction

VOID VD_BF_Init(BLOWFISH_CTX *ctx, UCHAR *key, LONG keyLen);
VOID VD_Blowfish_Encrypt(BLOWFISH_CTX *ctx, ULONG *xl, ULONG *xr);
VOID VD_Blowfish_Decrypt(BLOWFISH_CTX *ctx, ULONG *xl, ULONG *xr);

DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry (
    IN PDRIVER_OBJECT   DriverObject,
    IN PUNICODE_STRING  RegistryPath
);

DRIVER_UNLOAD VD_Unload;
VOID VD_Unload (
    IN PDRIVER_OBJECT   DriverObject
);

__drv_dispatchType(IRP_MJ_CLOSE) 
__drv_dispatchType(IRP_MJ_CREATE)
NTSTATUS VD_CreateClose (
    IN PDEVICE_OBJECT   DeviceObject,
    IN PIRP             Irp
);


__drv_dispatchType(IRP_MJ_READ)
__drv_dispatchType(IRP_MJ_WRITE)  
DRIVER_DISPATCH VD_ReadFile;
NTSTATUS VD_ReadWrite (
    IN PDEVICE_OBJECT   DeviceObject,
    IN PIRP             Irp
);


__drv_dispatchType(IRP_MJ_DEVICE_CONTROL) 
DRIVER_DISPATCH VD_DeviceControl;
NTSTATUS VD_DeviceControl (
    IN PDEVICE_OBJECT   DeviceObject,
    IN PIRP             Irp
);

__drv_dispatchType(IRP_MJ_PNP) 
DRIVER_DISPATCH VD_PnP;
NTSTATUS VD_PnP(
			IN PDEVICE_OBJECT DeviceObject,
		  IN PIRP Irp
);


NTSTATUS VD_CreateDevice (
    IN PDRIVER_OBJECT   DriverObject,
    IN LONG            Number
);


NTSTATUS VD_DeleteDevice(
		LONG		DeviceNumber
);

NTSTATUS VD_CheckFile(
	IN PDEVICE_OBJECT   DeviceObject,
	IN PIRP             Irp
);


NTSTATUS VD_OpenFile (
    IN PDEVICE_OBJECT   DeviceObject,
    IN PIRP             Irp
);

NTSTATUS VD_CloseFile (
    IN PDEVICE_OBJECT   DeviceObject,
    IN PIRP             Irp
);

KSTART_ROUTINE MultiVDD_ThreadHandler;
VOID VD_ThreadHandler (
    IN PVOID            Context
);


NTSTATUS VD_FlushFileBuffer(
					IN HANDLE FileHandle
);


#endif
